package com.yuandian.middle.platform.service.impl;

import com.yuandian.api.middle_platform.po.*;
import com.yuandian.api.middle_platform.vo.*;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.middle.platform.enums.ResponseSpeedEnum;
import com.yuandian.middle.platform.mapper.*;
import com.yuandian.middle.platform.service.IIndicatorDataService;
import com.yuandian.middle.platform.utils.CommonUtils;
import com.yuandian.middle.platform.utils.CustomCalculateRate;
import com.yuandian.po.MergeDataConfig;
import com.yuandian.po.MergeField;
import com.yuandian.utils.MathUtil;
import com.yuandian.utils.MergeDataUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;

/**
 * 说明：能力或服务指标数据查询接口实现
 * @Author tianlr
 * @Date 2023/5/18 10:35
 */

@Service
public class IndicatorDataServiceImpl implements IIndicatorDataService {

    @Autowired
    private CommonStatisticsMapper commonStatisticsMapper;
    @Autowired
    private ApiSdkStatisticsMapper apiSdkStatisticsMapper;
    @Autowired
    private InterruptTimeMapper interruptTimeMapper;
    @Autowired
    private SaasPaasStatisticsMapper saasPaasStatisticsMapper;
    @Autowired
    private UserCountMapper userCountMapper;
    @Autowired
    private H5StatisticsMapper h5StatisticsMapper;
    @Autowired
    private AbilityServerMapper abilityServerMapper;

    /**
     * 询能力服务对应的指标数据（API、SDK）
     * @return
     */
    @Override
    public R selectDataByInvocationModeApiSdk(OrgAbilityParam param) {
        ApiSdkDataVo vo = new ApiSdkDataVo();
        //查询响应指标（成功次数、超时次数、客户端失败次数、服务端失败次数、响应耗时）
        getResponseIndex(param, vo);
        //查询服务是否频繁访问，如果存在频繁访问的服务，则需要查询中断耗时指标
        List<AbilityServerPojo> serverList = abilityServerMapper.selectAbilityServerByAbility(param.getAbilityCode(), param.getServiceCode());
        //频繁访问变量
        int frequentAccess = 2;
        //非频繁访问变量
        int noFrequentAccess = 2;
        if (serverList != null && serverList.size() > 0) {
            for (AbilityServerPojo pojo : serverList) {
                //0: 非频繁访问的服务
                if (pojo.getIsFrequentAccess() == 0) {
                    noFrequentAccess = 0;
                } else {
                    frequentAccess = 1;
                }
                //如果都小于2，说明该能力下，既有频繁访问的服务也有非频繁访问的服务
                if (noFrequentAccess < 2 && frequentAccess < 2) {
                    break;
                }
            }
        }
        //查询中断耗时指标数据（为1，代表存在频繁访问的服务，因此需要显示中断耗时指标）
        if (frequentAccess == 1) {
            vo.setIsInterruptIntervalTime(1);
            List<InterruptTimePojo> interruptTimeList = interruptTimeMapper.selectInterruptTimeSnapshot(param);
            if (interruptTimeList != null && interruptTimeList.size() > 0) {
                InterruptTimePojo pojo = interruptTimeList.get(0);
                if (pojo != null) {
                    vo.setInterruptIntervalTime(pojo.getInterruptIntervalTime());
                }
            }
        }
        //为0，代表存在非频繁访问的服务，因此需要显示中断次数指标
        if (noFrequentAccess == 0) {
            vo.setIsInterruptCount(1);
        }
        //查询API和SDK指标数据（调用量、业务级成功次数、中断次数）
        List<ApiSdkStatisticsPojo> apiSdkList = apiSdkStatisticsMapper.selectApiOrSdkSnapshot(param);
        if (apiSdkList != null && apiSdkList.size() > 0) {
            ApiSdkStatisticsPojo pojo = apiSdkList.get(0);
            if (pojo != null) {
                vo.setReqCount(pojo.getReqCount());
                vo.setInterruptCount(pojo.getInterruptCount());
                vo.setBusinessSuccessRate(CommonUtils.longDiv(pojo.getBusinessSuccessCount(), pojo.getReqCount()) * 100);
            }
        }
        return R.ok(vo);
    }

    /**
     * 查询能力服务对应的指标数据（PaaS、SaaS）
     * @return
     */
    @Override
    public R selectDataByInvocationModePaaSaas(OrgAbilityParam param) {
        SaasPaasDataVo vo = new SaasPaasDataVo();
        //查询响应指标（成功次数、超时次数、客户端失败次数、服务端失败次数、平均响应耗时、系统级成功率）
        getResponseIndex(param, vo);
        //查询PaaS和SaaS指标数据（登录成功次数、登录接口被调用次数、核心页面浏览量）
        List<SaasPaasStatisticsPojo> list = saasPaasStatisticsMapper.selectPaaSOrSaaSSnapshot(param);
        if (list != null && list.size() > 0) {
            SaasPaasStatisticsPojo pojo = list.get(0);
            if (pojo != null) {
                vo.setLoginCount(pojo.getLoginCount());
                vo.setLoginSuccessCount(pojo.getLoginSuccessCount());
                vo.setLoginSuccessRate(CommonUtils.longDiv(pojo.getLoginSuccessCount(), pojo.getLoginCount()) * 100);
                vo.setCorePageReqCount(pojo.getCorePageReqCount());
            }
        }
        //查询用户量
        List<UserCountPojo> userList = userCountMapper.selectUserCount(param);
        if (userList != null && userList.size() > 0) {
            vo.setUserNumber(userList.size());
        }
        return R.ok(vo);
    }

    /**
     * 查询能力服务对应的指标数据（H5）
     * @return
     */
    @Override
    public R selectDataByInvocationModeH5(OrgAbilityParam param) {
        H5DataVo vo = new H5DataVo();
        //查询响应指标（成功次数、超时次数、客户端失败次数、服务端失败次数、平均响应耗时、系统级成功率）
        getResponseIndex(param, vo);
        //查询浏览量
        List<H5StatisticsPojo> h5List = h5StatisticsMapper.selectH5Snapshot(param);
        if (h5List != null && h5List.size() > 0) {
            H5StatisticsPojo pojo = h5List.get(0);
            if (pojo != null) {
                vo.setReqCount(pojo.getReqCount());
            }
        }
        //查询用户量
        List<UserCountPojo> userList = userCountMapper.selectUserCount(param);
        if (userList != null && userList.size() > 0) {
            vo.setUserNumber(userList.size());
        }
        return R.ok(vo);
    }

    /**
     * 查询能力服务对应的流量趋势数据
     * @param param
     * @return
     */
    @Override
    public R selectDataFlow(OrgAbilityParam param) {
        String startTime = param.getStartTime();
        String endTime = param.getEndTime();
        //获取指定时间范围对应的数据
        List<CommonStatisticsPojo> currentList = commonStatisticsMapper.selectByteAndPackage(param);
        //补齐数据
        completion(currentList, param);

        //获取前一天指定时间范围对应的数据
        param.setStartTime(CommonUtils.dateFormatString(CommonUtils.addDay(CommonUtils.stringFormatDate(startTime, null), -1), null));
        param.setEndTime(CommonUtils.dateFormatString(CommonUtils.addDay(CommonUtils.stringFormatDate(endTime, null), -1), null));
        List<CommonStatisticsPojo> day1List = commonStatisticsMapper.selectByteAndPackage(param);
        //补齐数据
        completion(day1List, param);

        //获取上一周指定时间范围对应的数据
        param.setStartTime(CommonUtils.dateFormatString(CommonUtils.addDay(CommonUtils.stringFormatDate(startTime, null), -7), null));
        param.setEndTime(CommonUtils.dateFormatString(CommonUtils.addDay(CommonUtils.stringFormatDate(endTime, null), -7), null));
        List<CommonStatisticsPojo> day7List = commonStatisticsMapper.selectByteAndPackage(param);
        //补齐数据
        completion(day7List, param);

        List<FlowDataVo> dataList = new ArrayList<>();
        if (currentList != null && currentList.size() > 0) {
            CommonStatisticsPojo currentPojo = null, day1Pojo = null, day7Pojo = null;
            FlowDataVo flowDataVo = null;
            for(int i = 0; i < currentList.size(); i++) {
                flowDataVo = new FlowDataVo();
                currentPojo = currentList.get(i);
                if (currentPojo != null) {
                    flowDataVo.setCycleTime(currentPojo.getCycleTime());
                    flowDataVo.setCurrentBytesTotal(currentPojo.getBytesTotal());
                    flowDataVo.setCurrentPackageTotal(currentPojo.getPackageTotal());
                }
                day1Pojo = day1List != null && day1List.size() > i ? day1List.get(i) : null;
                if (day1Pojo != null) {
                    flowDataVo.setDay1BytesTotal(day1Pojo.getBytesTotal());
                    flowDataVo.setDay1PackageTotal(day1Pojo.getPackageTotal());
                }
                day7Pojo = day7List != null && day7List.size() > i ? day7List.get(i) : null;
                if (day7Pojo != null) {
                    flowDataVo.setDay7BytesTotal(day7Pojo.getBytesTotal());
                    flowDataVo.setDay7PackageTotal(day7Pojo.getPackageTotal());
                }
                dataList.add(flowDataVo);
            }
        }

        // 归并数据
        List<MergeField> mergeFieldList = new ArrayList<>();
        //当前流量数据
        mergeFieldList.add(new MergeField("currentBytesTotal"));
        mergeFieldList.add(new MergeField("currentBytesTotalPer", new CustomCalculateRate("currentBytesTotal")));
        mergeFieldList.add(new MergeField("currentPackageTotal"));
        mergeFieldList.add(new MergeField("currentPackageTotalPer", new CustomCalculateRate("currentPackageTotal")));
        //过去一天流量数据
        mergeFieldList.add(new MergeField("day1BytesTotal"));
        mergeFieldList.add(new MergeField("day1BytesTotalPer", new CustomCalculateRate("day1BytesTotal")));
        mergeFieldList.add(new MergeField("day1PackageTotal"));
        mergeFieldList.add(new MergeField("day1PackageTotalPer", new CustomCalculateRate("day1PackageTotal")));
        //过去七天流量数据
        mergeFieldList.add(new MergeField("day7BytesTotal"));
        mergeFieldList.add(new MergeField("day7BytesTotalPer", new CustomCalculateRate("day7BytesTotal")));
        mergeFieldList.add(new MergeField("day7PackageTotal"));
        mergeFieldList.add(new MergeField("day7PackageTotalPer", new CustomCalculateRate("day7PackageTotal")));

        param.setStartTime(startTime);
        param.setEndTime(endTime);
        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                FlowDataVo.class,
                dataList,
                param.getStartTime(),
                param.getEndTime(),
                mergeFieldList)
                .build());
        //如果最后一个点的时间与结束时间相同，则去掉
        CommonUtils.removeLastPoint(map, param.getEndTime());
        return R.ok(map);
    }

    /**
     * 查询能力或服务对应的响应量趋势数据
     * @param param
     * @return
     */
    @Override
    public R selectDataResponse(OrgAbilityParam param) {
        //查询响应指标趋势（成功次数、超时次数、客户端失败次数、服务端失败次数、响应耗时）
        List<CommonStatisticsPojo> dataList = commonStatisticsMapper.selectResponseTrend(param);

        // 归并数据
        List<MergeField> mergeFieldList = new ArrayList<>();
        mergeFieldList.add(new MergeField("systemSuccessCount"));
        mergeFieldList.add(new MergeField("timeoutCount"));
        mergeFieldList.add(new MergeField("clientFailCount"));
        mergeFieldList.add(new MergeField("serverFailCount"));
        mergeFieldList.add(new MergeField("serverResponseTime"));
        mergeFieldList.add(new MergeField("avgServerResponseTime", ((map, inx, labelTimeUsecList, scale) -> {
            Double response = map.get("systemSuccessCountList").get(inx) + map.get("timeoutCountList").get(inx)
                    + map.get("clientFailCountList").get(inx) + map.get("serverFailCountList").get(inx);
            Double totalResTimes = map.get("serverResponseTimeList").get(inx);
            return MathUtil.divideKeepNoFormat(totalResTimes, response, 2);
        })));

        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                CommonStatisticsPojo.class,
                dataList,
                param.getStartTime(),
                param.getEndTime(),
                mergeFieldList)
                .build());
        //如果最后一个点的时间与结束时间相同，则去掉
        CommonUtils.removeLastPoint(map, param.getEndTime());
        return R.ok(map);
    }

    /**
     * 查询能力服务对应调用量趋势数据（API、SDK）
     * @return
     */
    @Override
    public R selectDataReqCountTrend(OrgAbilityParam param) {
        //查询调用量数据
        List<ApiSdkStatisticsPojo> dataList = apiSdkStatisticsMapper.selectReqCountTrend(param);
        // 归并数据
        List<MergeField> mergeFieldList = new ArrayList<>();
        mergeFieldList.add(new MergeField("reqCount"));
        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                ApiSdkStatisticsPojo.class,
                dataList,
                param.getStartTime(),
                param.getEndTime(),
                mergeFieldList)
                .build());
        //如果最后一个点的时间与结束时间相同，则去掉
        CommonUtils.removeLastPoint(map, param.getEndTime());
        return R.ok(map);
    }

    /**
     * 查询能力服务对应核心页面浏览量趋势数据（PaaS、SaaS）
     * @return
     */
    @Override
    public R selectDataCorePageViewTrend(OrgAbilityParam param) {
        //查询PaaS和SaaS核心页面浏览量趋势数据
        List<SaasPaasStatisticsPojo> dataList = saasPaasStatisticsMapper.selectCorePageViewTrend(param);
        // 归并数据
        List<MergeField> mergeFieldList = new ArrayList<>();
        mergeFieldList.add(new MergeField("corePageReqCount"));
        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                SaasPaasStatisticsPojo.class,
                dataList,
                param.getStartTime(),
                param.getEndTime(),
                mergeFieldList)
                .build());
        //如果最后一个点的时间与结束时间相同，则去掉
        CommonUtils.removeLastPoint(map, param.getEndTime());
        return R.ok(map);
    }

    /**
     * 查询能力服务对应浏览量趋势数据（H5）
     * @return
     */
    @Override
    public R selectDataPageViewTrend(OrgAbilityParam param) {
        //查询H5浏览量趋势数据
        List<H5StatisticsPojo> dataList = h5StatisticsMapper.selectPageViewTrend(param);
        // 归并数据
        List<MergeField> mergeFieldList = new ArrayList<>();
        mergeFieldList.add(new MergeField("reqCount"));
        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                H5StatisticsPojo.class,
                dataList,
                param.getStartTime(),
                param.getEndTime(),
                mergeFieldList)
                .build());
        //如果最后一个点的时间与结束时间相同，则去掉
        CommonUtils.removeLastPoint(map, param.getEndTime());
        return R.ok(map);
    }

    /**
     * 查询响应耗时分布
     * @param param
     * @return
     */
    @Override
    public R selectResponseTimeDistribution(OrgAbilityParam param) {
        //查询响应耗时分布（快速响应请求数、正常响应请求数、慢响应请求数、缓慢响应请求数）
        List<CommonStatisticsPojo> list = commonStatisticsMapper.selectResponseTimeDistribution(param);
        long fast = 0, normal = 0, slow = 0, slowest = 0, timeOut = 0;
        if (list != null && list.size() > 0) {
            CommonStatisticsPojo pojo = list.get(0);
            if (pojo != null) {
                fast = pojo.getFastResponseCount();
                normal = pojo.getNormalResponseCount();
                slow = pojo.getSlowResponseCount();
                slowest = pojo.getSlowestResponseCount();
                timeOut = pojo.getTimeoutCount();
            }
        }
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        map.put(ResponseSpeedEnum.FAST.getItemValue(), fast);
        map.put(ResponseSpeedEnum.NORMAL.getItemValue(), normal);
        map.put(ResponseSpeedEnum.SLOW.getItemValue(), slow);
        map.put(ResponseSpeedEnum.SLOWEST.getItemValue(), slowest);
        map.put(ResponseSpeedEnum.TIMEOUT.getItemValue(), timeOut);
        return R.ok(map);
    }

    /**
     * 查询能力或服务对应的响应量快照数据
     * @param param
     * @return
     */
    @Override
    public R selectDataResponseSnapshot(OrgAbilityParam param) {
        CommonDataVo vo = new CommonDataVo();
        getResponseIndex(param, vo);
        return R.ok(vo);
    }

    /**
     * 获取共同的指标（成功次数、超时次数、客户端失败次数、服务端失败次数、平均响应耗时、系统级成功率）
     * @param param
     * @param vo
     */
    private void getResponseIndex(OrgAbilityParam param, CommonDataVo vo) {
        //查询响应指标（成功次数、超时次数、客户端失败次数、服务端失败次数、响应耗时）
        List<CommonStatisticsPojo> commonList = commonStatisticsMapper.selectResponseSnapshot(param);
        if (commonList != null && commonList.size() > 0) {
            CommonStatisticsPojo pojo = commonList.get(0);
            if (pojo != null) {
                vo.setClientFailCount(pojo.getClientFailCount());
                vo.setServerFailCount(pojo.getServerFailCount());
                vo.setTimeoutCount(pojo.getTimeoutCount());
                vo.setSystemSuccessCount(pojo.getSystemSuccessCount());
                long number = pojo.getClientFailCount() + pojo.getServerFailCount() + pojo.getSystemSuccessCount();
                if (number == 0) {
                    number = 1;
                }
                vo.setAvgServerResponseTime(pojo.getServerResponseTime() / number);
                number = pojo.getClientFailCount() + pojo.getServerFailCount() + pojo.getSystemSuccessCount() + pojo.getTimeoutCount();
                vo.setSystemSuccessRate(CommonUtils.longDiv(pojo.getSystemSuccessCount(), number) * 100);
            }
        }
    }

    /**
     * 补齐数据
     * @param list
     * @param param
     */
    private void completion(List<CommonStatisticsPojo> list, OrgAbilityParam param) {
        if (list == null) {
            list = new ArrayList<>();
        }
        //记录从数据中查询出来的所有时间点
        Set<String> set = new HashSet<String>();
        for(CommonStatisticsPojo pojo : list) {
            set.add(pojo.getCycleTime());
        }
        //查询时间有可能有秒，因此需要做一下处理
        long startTimeLong = 0, startTimeLongTmp1 = 0, startTimeLongTmp2 = 0;
        startTimeLongTmp1 = CommonUtils.stringFormatTimestamp(param.getStartTime(), CommonUtils.dateFormatMinute);
        startTimeLongTmp2 = CommonUtils.stringFormatTimestamp(param.getStartTime(), null);
        if (startTimeLongTmp1 == startTimeLongTmp2) {
            startTimeLong = startTimeLongTmp1;
        } else {
            startTimeLong = startTimeLongTmp1 + 60;
        }
        long endTimeLong = 0, endTimeLongTmp1 = 0, endTimeLongTmp2 = 0;
        endTimeLongTmp1 = CommonUtils.stringFormatTimestamp(param.getEndTime(), CommonUtils.dateFormatMinute);
        endTimeLongTmp2 = CommonUtils.stringFormatTimestamp(param.getEndTime(), null);
        if (endTimeLongTmp1 == endTimeLongTmp2) {
            endTimeLong = endTimeLongTmp1;
        } else {
            endTimeLong = endTimeLongTmp1 + 60;
        }
        String str = "";
        CommonStatisticsPojo pojo = null;
        for(long tmp = startTimeLong; tmp < endTimeLong; ) {
            str = CommonUtils.timestampFormatString(tmp, null);
            if (!set.contains(str)){
                pojo = new CommonStatisticsPojo();
                pojo.setCycleTime(str);
                list.add(pojo);
            }
            tmp = tmp + 60;
        }
        Collections.sort(list, new Comparator<CommonStatisticsPojo>() {
            @Override
            public int compare(CommonStatisticsPojo o1, CommonStatisticsPojo o2) {
                return o1.getCycleTime().compareTo(o2.getCycleTime());
            }
        });
    }
}
